Next: Packages that Change Keymaps, Previous: Rudimentary Changes, Up: Customization [Contents][Index]
Viper lets you define hot keys, i.e., you can associate keyboard keys such as F1, Help, PgDn, etc., with Emacs Lisp functions (that may already exist or that you will write). Each key has a “preferred form” in Emacs. For instance, the Up key’s preferred form is [up], the Help key’s preferred form is [help], and the Undo key has the preferred form [f14]. You can find out the preferred form of a key by typing M-x describe-key-briefly and then typing the key you want to know about.
Under the X Window System, every keyboard key emits its preferred form, so you can just type
(global-set-key [f11] 'calendar) ; L1, Stop (global-set-key [f14] 'undo) ; L4, Undo
to bind L1 (a key that exists on some SUN workstations) so it
will invoke the Emacs Calendar and to bind L4 so it will undo
changes. However, on a dumb terminal or in an Xterm window, even
the standard arrow keys may not emit the right signals for Emacs
to understand. To let Emacs know about those keys, you will have
to find out which key sequences they emit by typing
C-q and then the key (you should switch to Emacs state
first). Then you can bind those sequences to their preferred
forms using input-decode-map as follows:
(cond ((string= (getenv "TERM") "xterm") (define-key input-decode-map "\e[192z" [f11]) ; L1 (define-key input-decode-map "\e[195z" [f14]) ; L4, Undo
The above illustrates how to do this for Xterm. On VT100, you would have to replace "xterm" with "vt100" and also change the key sequences (the same key may emit different sequences on different types of terminals).
The above keys are global, so they are overwritten by the local maps defined by the major modes and by Viper itself. Therefore, if you wish to change a binding set by a major mode or by Viper, read this.
Viper users who wish to specify their own key bindings should
be concerned only with the following three keymaps:
viper-vi-global-user-map for Vi state commands,
viper-insert-global-user-map for Insert state
commands, and viper-emacs-global-user-map for Emacs
state commands (note: customized bindings for Emacs state made to
viper-emacs-global-user-map are not
inherited by Insert state).
For more information on Viper keymaps, see the header of the
file viper.el. If you wish to change a Viper
binding, you can use the define-key command, to
modify viper-vi-global-user-map,
viper-insert-global-user-map, and
viper-emacs-global-user-map, as explained below.
Each of these key maps affects the corresponding Viper state. The
keymap viper-insert-global-user-map also affects
Viper’s Replace state.
If you want to bind a key, say C-v, to the function that scrolls page down and to make 0 display information on the current buffer, putting this in your Viper customization file will do the trick in Vi state:
(define-key viper-vi-global-user-map "\C-v" 'scroll-down)
To set a key globally,
(define-key viper-emacs-global-user-map "\C-c m" 'smail) (define-key viper-vi-global-user-map "0" 'viper-info-on-file)
Note, however, that this binding may be overwritten by other keymaps, since the global keymap has the lowest priority. To make sure that nothing will override a binding in Emacs state, you can write this:
(define-key viper-emacs-global-user-map "\C-c m" 'smail)
To customize the binding for C-h in Insert state:
(define-key viper-insert-global-user-map "\C-h" 'my-del-backwards-function)
Each Emacs command key calls some Lisp function. If you have enabled the Help, (see Rudimentary Changes) C-h k will show you the function for each specific key; C-h b will show all bindings, and C-h m will provide information on the major mode in effect. If Help is not enabled, you can still get help in Vi state by prefixing the above commands with \, e.g., \ C-h k (or you can use the Help menu in the menu bar, if Emacs runs under X).
Viper users can also change bindings on a per major mode
basis. As with global bindings, this can be done separately for
each of the three main Viper states. To this end, Viper provides
the function viper-modify-major-mode.
To modify keys in Emacs state for
my-favorite-major-mode, the user needs to create a
sparse keymap, say, my-fancy-map, bind whatever keys
necessary in that keymap, and put
(viper-modify-major-mode 'dired-mode 'emacs-state my-fancy-map)
in your Viper customization file. To do the same in Vi and
Insert states, you should use vi-state and
insert-state. Changes in Insert state are also in
effect in Replace state. For instance, suppose that the user
wants to use dd in Vi state under Dired mode to delete
files, u to unmark files, etc. The following code in
the Viper customization file will then do the job:
(setq my-dired-modifier-map (make-sparse-keymap)) (define-key my-dired-modifier-map "dd" 'dired-flag-file-deletion) (define-key my-dired-modifier-map "u" 'dired-unmark) (viper-modify-major-mode 'dired-mode 'vi-state my-dired-modifier-map)
A Vi purist may want to modify Emacs state under Dired mode so that k, l, etc., will move around in directory buffers, as in Vi. Although this is not recommended, as these keys are bound to useful Dired functions, the trick can be accomplished via the following code:
(setq my-dired-vi-purist-map (make-sparse-keymap))
(define-key my-dired-vi-purist-map "k" 'viper-previous-line)
(define-key my-dired-vi-purist-map "l" 'viper-forward-char)
(viper-modify-major-mode 'dired-mode
'emacs-state my-dired-vi-purist-map)
Yet another way to customize key bindings in a major mode is
to edit the list viper-major-mode-modifier-list
using the customization widget. (This
variable is in the Viper-misc customization group.) The elements
of this list are triples of the form: (major-mode viper-state
keymap), where the keymap contains bindings that are supposed to
be active in the given major mode and the given viper-state.
Effects similar to key binding changes can be achieved by defining Vi keyboard macros using the Ex commands :map and :map!. The difference is that multi-key Vi macros do not override the keys they are bound to, unless these keys are typed in quick succession. So, with macros, one can use the normal keys alongside with the macros. If per-mode modifications are needed, the user can try both ways and see which one is more convenient. See Vi Macros, for details.
Note: in major modes that come up in Emacs state by
default, the aforesaid modifications may not take place
immediately (but only after the buffer switches to some other
Viper state and then back to Emacs state). To avoid this, one
should add viper-change-state-to-emacs to an
appropriate hook of that major mode. (Check the function
viper-set-hooks in viper.el for
examples.) However, if you did not set viper-always
to nil, chances are that you won’t need to
perform the above procedure, because Viper will take care of most
useful defaults.
Finally, Viper has a facility that lets the user define
per-buffer bindings, i.e., bindings that are in effect in some
specific buffers only. Unlike per-mode bindings described above,
per-buffer bindings can be defined based on considerations other
than the major mode. This is done via the function
viper-add-local-keys, which lets one specify
bindings that should be in effect in the current buffer only and
for a specific Viper state. For instance,
(viper-add-local-keys 'vi-state '(("ZZ" . TeX-command-master)
("ZQ" . viper-save-kill-buffer)))
redefines ZZ to invoke
TeX-command-master in vi-state and
ZQ to save-then-kill the current buffer. These
bindings take effect only in the buffer where this command is
executed. The typical use of this function is to execute the
above expression from within a function that is included in a
hook to some major mode. For instance, the above expression could
be called from a function, my-tex-init, which may be
added to tex-mode-hook as follows:
(add-hook 'tex-mode-hook 'my-tex-init)
When TeX mode starts, the hook is executed and the above Lisp expression is evaluated. Then, the bindings for ZZ and ZQ are changed in Vi command mode for all buffers in TeX mode.
Another useful application is to bind ZZ to
send-mail in the Mail mode buffers (the specifics of
this depend on which mail package you are using,
rmail, mh-e, vm, etc. For
instance, here is how to do this for mh-e, the Emacs
interface to MH:
(defun mh-add-vi-keys ()
"Set up ZZ for MH-e and XMH."
(viper-add-local-keys 'vi-state '(("ZZ" . mh-send-letter))))
(add-hook 'mh-letter-mode-hook 'mh-add-vi-keys)
You can also use viper-add-local-keys to set per
buffer bindings in Insert state and Emacs state by passing as a
parameter the symbols insert-state and
emacs-state, respectively. As with global bindings,
customized local bindings done to Emacs state are not inherited
by Insert state.
On rare occasions, local keys may be added by mistake. Usually
this is done indirectly, by invoking a major mode that adds local
keys (e.g., shell-mode redefines RET). In such a case, exiting the wrong major mode
won’t rid you from unwanted local keys, since these keys
are local to Viper state and the current buffer, not to the major
mode. In such situations, the remedy is to type M-x
viper-zap-local-keys.
So much about Viper-specific bindings. See Customization in The GNU Emacs Manual, and the Emacs quick reference card for the general info on key bindings in Emacs.
Next: Packages that Change Keymaps, Previous: Rudimentary Changes, Up: Customization [Contents][Index]